/// HCC转FHIR工具使用示例，演示基于文件和数据库的互联互通转FHIR并上传FHIR资源仓库
Class HCC.Utils.FHIRUpload Extends %RegisteredObject
{

// do ##class(HCC.Utils.FHIRUpload).UploadFromSQLByRange()

// do ##class(HCC.Utils.FHIRUpload).UploadFromFile()

/// 从SQL数据源获取互联互通文档，转换并提交FHIR资源仓库的示例
/// 输入参数pSQL: 获取数据的SQL语句,应返回2个字段：文档Stream字段(第一个)和可以标识文档唯一性的字段(第二个)
/// switch on debug mode: Set ^HCC("FHIR","Transfer","Debug")=1
/// switch off debug mode: Set ^HCC("FHIR","Transfer","Debug")=0
/// set debug path: Set ^HCC("FHIR","Transfer","DebugPath")="/ISC/FHIROUTPUT/"
/// in debug mode, it will save generated fhir into directory for debug purpose, remember to switch off for live.
/// This method need a SQL statement as input
/// The SQL need to return 2 columns: 1st one is document content as stream, 2nd one is a unique value to identify the document
/// for example: "SELECT DOCUMENT,PK FROM Source.hdr_cda_index where PATIENT_ID='0003435759' and VISIT_ID='71295242' and PK='-1152921504583822096_EMR-SD-08'"
/// POC target range: VISIT_ID>=91498790 and VISIT_ID<=92312777
/// current run: VISIT_ID>=91498790 and VISIT_ID<=91498890
ClassMethod UploadFromSQL(pSQL = "SELECT DOCUMENT,PK FROM Source.hdr_cda_index where VISIT_ID>=91498790 and VISIT_ID<=91498890") As %Status
{
	Set tSC = $$$OK
	Set x="<?xml version=""1.0"" encoding=""UTF-8""?>"
	
	// 初始化HCC转FHIR工具
	Set tXSLPath = "file:///"_$SYSTEM.Util.InstallDirectory()_"csp/xslt/HCC/HCC2SDA.xsl"
    Set tTranformer=##class(HCC.Utils.HCC2FHIR).%New(tXSLPath)
	
	Set tStm = ##class(%SQL.Statement).%New()
	Set tSC = tStm.%Prepare(.pSQL)
	Quit:($$$ISERR(tSC)) tSC
	
	Set tRS = tStm.%Execute()
	While tRS.%Next()
  	{
		Set tTmp = tRS.%GetData(1),tDocPK = tRS.%GetData(2), tLen = 32000
		Set tDocContent=tTmp.Read(.tLen)
		While tLen>0
		{
			Set tDocContent=tDocContent_tTmp.Read(.tLen)
		}
		// base64 decode
		Set tPlainContent = $system.Encryption.Base64Decode(tDocContent)
		Set tPlainContent = $ZCVT(tPlainContent,"I","UTF8")
		// 去除XML标头
		Set tPlainContent = $Replace(tPlainContent,x,"")
   	
		set tStream = ##class(%Stream.TmpCharacter).%New()
		Do tStream.Write(tPlainContent)
		// 转换FHIR
		Set tFHIR=""			
		Set tSC = tTranformer.TransferHCCDocStream2FHIR(tStream,.tFHIR)
		Return:($$$ISERR(tSC)) tSC
		
		//debug mode
		If ($GET(^HCC("FHIR","Transfer","Debug"))=1) && ($GET(^HCC("FHIR","Transfer","DebugPath"))'="")
		{
			Set tFHIRDebugPath=$G(^HCC("FHIR","Transfer","DebugPath"))
			Set tDebug=##class(%Stream.FileCharacter).%New()
		    Set tDebug.TranslateTable="UTF8"
			Set tDebugFile= tFHIRDebugPath_tDocPK_".json"
			Set tSC=tDebug.LinkToFile(tDebugFile)
			
	    	Do tDebug.Write(tFHIR.Read())
	    	Do tDebug.%Save(),tDebug.%Close()
	    	Do tFHIR.Rewind()
		}
    	
    	// revise FHIR based on FHIR repository
    	Set tTarget=""
    	Set tSC = ##class(HCC.Utils.FHIRTransformer).ReviseFHIRStream(tFHIR,.tTarget)
    	Return:($$$ISERR(tSC)) tSC
		// upload to FHIR repository
		Set tSC = ..UploadSingleStream(,,tTarget)
		Return:($$$ISERR(tSC)) tSC
		w tDocPK," uploaded",!
		
    	Set tPlainContent=""
    	Do tTmp.%Close(),tTarget.%Close(),tFHIR.%Close(),tStream.%Close()
	}
	Do tRS.%Close()
	Q tSC
}

/// data source, mysql, is very slow. so changed logic to get limited record each time.
ClassMethod UploadFromSQLByRange(pStartDate = "20220223", pDateRange = 1) As %Status
{
	;Set tSQL = "SELECT DOCUMENT,PK FROM Source.hdr_cda_index where VISIT_ID=?"
	Set tStartDate = $ZDH(pStartDate,8)
	Set tSQL = "SELECT DOCUMENT,PK FROM nullschema.JHDL_78_HDR_CDA_INDEX where admission_time>=? and admission_time<? order by id"

	Set tSC = $$$OK
	Set x="<?xml version=""1.0"" encoding=""UTF-8""?>"
	Set tXSLPath = "file:///"_$SYSTEM.Util.InstallDirectory()_"csp/xslt/HCC/HCC2SDA.xsl"
    Set tTranformer=##class(HCC.Util.FHIRTranformer).%New(tXSLPath)
	
	for tInd = 1:1:pDateRange
	{
		try
		{
			Set tCount=0
			Set tStm = ##class(%SQL.Statement).%New()
			Set tSC = tStm.%Prepare(.tSQL)
			Return:($$$ISERR(tSC)) tSC
			
			Set tStart = tStartDate+tInd,tFinish = tStart+1
			Set ^HCCStatus("tBegin") = $ZD(tStart,8),^HCCStatus("tEnd")=$ZD(tFinish,8)
			
			w ^HCCStatus("tBegin"),"-",^HCCStatus("tEnd"), " started",!
			Set tRS = tStm.%Execute(^HCCStatus("tBegin"),^HCCStatus("tEnd"))
			While tRS.%Next()
		  	{
			  	D $I(tCount)
				Set tTmp = tRS.%GetData(1),tDocPK = tRS.%GetData(2), tLen = 32000, ^HCCStatus("tDocPK")=tDocPK
				Set tDocContent=tTmp.Read(.tLen)
				While tLen>0
				{
					Set tDocContent=tDocContent_tTmp.Read(.tLen)
				}
				// base64 decode
				Set tPlainContent = $system.Encryption.Base64Decode(tDocContent)
				Set tPlainContent = $ZCVT(tPlainContent,"I","UTF8")
				Set tPlainContent = $Replace(tPlainContent,x,"")
				
				//debug mode
				/*
				If ($GET(^HCC("FHIR","Transfer","Debug"))=1) && ($GET(^HCC("FHIR","Transfer","DebugPath"))'="")
				{
					Set tFHIRDebugPath=$G(^HCC("FHIR","Transfer","DebugPath"))
					Set tDebug=##class(%Stream.FileCharacter).%New()
				    Set tDebug.TranslateTable="UTF8"
					Set tDebugFile= tFHIRDebugPath_tDocPK_".xml"
					Set tSC=tDebug.LinkToFile(tDebugFile)
					;w tPlainContent,!
			    	Do tDebug.Write(tPlainContent)
			    	Do tDebug.%Save(),tDebug.%Close()
				}*/
		    	
		   	
				set tStream = ##class(%Stream.TmpCharacter).%New()
				Do tStream.Write(tPlainContent)
				// transform to FHIR
				Set tFHIR=""			
				Set tSC = tTranformer.TransferHCCDocStream2FHIR(tStream,.tFHIR)
				If ($$$ISERR(tSC))
				{
					w tDocPK,": Transfer to FHIR:",tSC,!
					Return tSC
				}
				
				//debug mode
				If ($GET(^HCC("FHIR","Transfer","Debug"))=1) && ($GET(^HCC("FHIR","Transfer","DebugPath"))'="")
				{
					Set tFHIRDebugPath=$G(^HCC("FHIR","Transfer","DebugPath"))
					Set tDebug=##class(%Stream.FileCharacter).%New()
				    Set tDebug.TranslateTable="UTF8"
					Set tDebugFile= tFHIRDebugPath_tDocPK_".json"
					Set tSC=tDebug.LinkToFile(tDebugFile)
					
			    	Do tDebug.Write(tFHIR.Read())
			    	Do tDebug.%Save(),tDebug.%Close()
			    	Do tFHIR.Rewind()
				}
		    	
		    	// revise FHIR based on FHIR repository
		    	Set tTarget=""
		    	Set tSC = ##class(HCC.Utils.FHIRTransformer).ReviseFHIRStream(tFHIR,.tTarget)
		    	If ($$$ISERR(tSC))
				{
					w tDocPK,":revise FHIR:",tSC,!
					Return tSC
				}
				// upload to FHIR repository
				Set tSC = ..UploadSingleStream(,,tTarget)
				If ($$$ISERR(tSC))
				{
					w tDocPK,":upload FHIR:",tSC,!
					Return tSC
				}
				w tDocPK,": uploaded",!
				
		    	Set tPlainContent=""
		    	Do tTmp.%Close(),tTarget.%Close(),tFHIR.%Close(),tStream.%Close()
			}
			Do tRS.%Close(),tStm.%Close()
			w tCount," processed",!
		}
		catch(e)
		{
			Set:($IsObject(%objlasterror)) ^HCCStatus($I(^HCCStatus),"Error",tDocPK)=$ZDT($h,8)_":"_$system.Status.GetErrorText(%objlasterror)
			Quit
		}
	}
	Q tSC
}

/// revise uploading FHIR files and upload
ClassMethod UploadFromFile(pSourceDir = "/isc/irishealth/csp/xslt/FHIROUT", pTargetDir = "C:\Users\DEMO\Desktop\CDA2FHIR\RevisedFHIR")
{
	set tST = ##class(%SQL.Statement).%New()
	set tSC = tST.%PrepareClassQuery("%File", "FileSet")
	if $$$ISERR(tSC) {write "%Prepare failed:" do $SYSTEM.Status.DisplayError(tSC) quit}

	set tRS = tST.%Execute(pSourceDir, "*.json;*.JSON")
	if (tRS.%SQLCODE '= 0) {write "%Execute failed:", !, "SQLCODE ", rset.%SQLCODE, ": ", rset.%Message quit}
	
	Set tSplit=$Case($system.Version.GetOS(),"Windows":"\",:"/")
	    
	while tRS.%Next()
	{
		Set tSourceFile=tRS.%Get("Name"), tFileName = $P(tSourceFile,tSplit,$L(tSourceFile,tSplit))
		Set tSource=##class(%Stream.FileBinary).%New()
		Set tSC=tSource.LinkToFile(tSourceFile)

		Set tTargetFile=pTargetDir_tSplit_tFileName
		Set tTarget=##class(%Stream.FileBinary).%New()
		;Set tTarget=##class(%Stream.FileCharacter).%New()
		;Set tTarget.TranslateTable="UTF8"
		Set tSC=tTarget.LinkToFile(tTargetFile)
		
		Set tSC = ##class(HCC.Utils.FHIRTransformer).ReviseFHIRStream(tSource,.tTarget)
		Set tSC = tTarget.%Save()
		// upload to FHIR repository
		;w tFileName,!
		Do ..UploadSingleFile(,,tTargetFile)
		
		Do tTarget.%Close(),tSource.%Close()
	}
	
	Do tRS.%Close()
	Quit
}

/// single stream upload
ClassMethod UploadSingleStream(pServiceType = "FHIRServer", pServiceName = "/csp/healthshare/fhirns/fhir/r4", pStream) As %Status
{
	Set tSC = $$$OK
	Set tDataLoader=##class(HS.FHIRServer.Tools.DataLoader).%New(pServiceType, pServiceName)
	Do pStream.Rewind()
	Set tSC = tDataLoader.SubmitResourceStream(pStream, "JSON", .tSentStreamSize, .tEntryCount, .tElapsed)
	w "StreamSize=",tSentStreamSize,"  EntryCount=",tEntryCount, "   Elapsed=",tElapsed,!
	Do tDataLoader.%Close()
	Quit tSC
}

/// single file upload
ClassMethod UploadSingleFile(pServiceType = "FHIRServer", pServiceName = "/csp/healthshare/fhirns/fhir/r4", pFile) As %Status
{
	Set tSC = $$$OK
	Set tFile=##class(%Stream.FileCharacter).%New()
	Set tFile.TranslateTable="UTF8"
	Set tSC=tFile.LinkToFile(pFile)

	Set tDataLoader=##class(HS.FHIRServer.Tools.DataLoader).%New(pServiceType, pServiceName)
	Set tSC = tDataLoader.SubmitResourceStream(tFile, "JSON", .tSentStreamSize, .tEntryCount, .tElapsed)
	w "StreamSize=",tSentStreamSize,"  EntryCount=",tEntryCount, "   Elapsed=",tElapsed,!
	Do tDataLoader.%Close()
	Quit tSC
}

/// revise uploading FHIR files and upload
ClassMethod ReviseFHIRFile(pServiceType = "FHIRServer", pSourceDir = "/isc/irishealth/csp/xslt/FHIROUT", pTargetDir = "/isc/irishealth/csp/xslt/RevisedFHIR")
{
	set tST = ##class(%SQL.Statement).%New()
	set tSC = tST.%PrepareClassQuery("%File", "FileSet")
	if $$$ISERR(tSC) {write "%Prepare failed:" do $SYSTEM.Status.DisplayError(tSC) quit}

	set tRS = tST.%Execute(pSourceDir, "*.json;*.JSON")
	if (tRS.%SQLCODE '= 0) {write "%Execute failed:", !, "SQLCODE ", rset.%SQLCODE, ": ", rset.%Message quit}
	
	Set tSplit=$Case($system.Version.GetOS(),"Windows":"\",:"/")
	    
	while tRS.%Next()
	{
		Set tSourceFile=tRS.%Get("Name"), tFileName = $P(tSourceFile,tSplit,$L(tSourceFile,tSplit))
		w tFileName,!
		Set tSource=##class(%Stream.FileBinary).%New()
		Set tSC=tSource.LinkToFile(tSourceFile)

		Set tTargetFile=pTargetDir_tSplit_tFileName
		Set tTarget=##class(%Stream.FileBinary).%New()
		;Set tTarget=##class(%Stream.FileCharacter).%New()
		;Set tTarget.TranslateTable="UTF8"
		Set tSC=tTarget.LinkToFile(tTargetFile)
		
		Set tSC = ##class(HCC.Utils.FHIRTransformer).ReviseFHIRStream(tSource,.tTarget)
		Set tSC = tTarget.%Save()
		// upload to FHIR repository
		w tFileName,!
		Do ..UploadSingleFile(pServiceType,,tTargetFile)
		
		Do tTarget.%Close(),tSource.%Close()
	}
	
	Do tRS.%Close()
	Quit
}

ClassMethod Test1(pSQL = "SELECT DOCUMENT,PK FROM Source.hdr_cda_index where PATIENT_ID='0003435759' and VISIT_ID='71295242' and DOCUMENT_CODE='EMR-SD-52'") As %Status
{
	Set tSC = $$$OK
	Set x="<?xml version=""1.0"" encoding=""UTF-8""?>"
	Set tXSLPath = "file:///"_$SYSTEM.Util.InstallDirectory()_"csp/xslt/HCC/HCC2SDA.xsl"
    Set tTranformer=##class(HCC.Util.FHIRTranformer).%New(tXSLPath)
	
	Set tStm = ##class(%SQL.Statement).%New()
	Set tSC = tStm.%Prepare(.pSQL)
	Quit:($$$ISERR(tSC)) tSC
	
	Set tRS = tStm.%Execute()
	While tRS.%Next()
  	{
		Set tTmp = tRS.%GetData(1),tDocPK = tRS.%GetData(2), tLen = 32000
		Set tDocContent=tTmp.Read(.tLen)
		While tLen>0
		{
			Set tDocContent=tDocContent_tTmp.Read(.tLen)
		}
		// base64 decode
		Set tPlainContent = $system.Encryption.Base64Decode(tDocContent)
		Set tPlainContent = $ZCVT(tPlainContent,"I","UTF8")
		Set tPlainContent = $Replace(tPlainContent,x,"")
   	
		Set tTarget=##class(%Stream.FileCharacter).%New()
	    Set tTarget.TranslateTable="UTF8"
		Set tTargetFile= "/ISC/FHIROUTPUT/"_tDocPK_".xml"
		Set tSC=tTarget.LinkToFile(tTargetFile)
		Do tTarget.Write(tPlainContent)
		Return:($$$ISERR(tSC)) tSC
		Do tTarget.%Save()
		
    	Set tPlainContent=""
    	Do tTmp.%Close(),tTarget.%Close()
	}
	Do tRS.%Close()
	Q tSC
}

ClassMethod Test()
{
	Set tSource=##class(%Stream.FileBinary).%New()
	Set tSourceFile= "/ISC/FHIROUTPUT/test.json"
	Set tSC=tSource.LinkToFile(tSourceFile)
		
	;set tStream = ##class(%Stream.TmpCharacter).%New()
	;Do tStream.Write(tPlainContent)
	
	Set tXSLPath = "file:///"_$SYSTEM.Util.InstallDirectory()_"csp/xslt/HCC/HCC2SDA.xsl"
    Set tTranformer=##class(HCC.Util.FHIRTranformer).%New(tXSLPath)
    Set tFHIR=""
	w tTranformer.TransferHCCDocStream2FHIR(tSource,.tFHIR),!
	w tFHIR.Read(),!
	/*
	Set tTarget=##class(%Stream.FileCharacter).%New()
    Set tTarget.TranslateTable="UTF8"
	Set tTargetFile= "/ISC/FHIROUTPUT/test.json"
	Set tSC=tTarget.LinkToFile(tTargetFile)
	Quit:($$$ISERR(tSC))
	
	Do tTarget.Write(tFHIR.Read())
	Do tTarget.%Save(),tTarget.%Close(),tFHIR.%Close()*/
}

ClassMethod Debug(pDocPK)
{
	Set tSQL = "SELECT DOCUMENT,PK FROM nullschema.JHDL_78_HDR_CDA_INDEX where pk=?"

	Set tSC = $$$OK
	Set x="<?xml version=""1.0"" encoding=""UTF-8""?>"
	Set tXSLPath = "file:///"_$SYSTEM.Util.InstallDirectory()_"csp/xslt/HCC/HCC2SDA.xsl"
    Set tTranformer=##class(HCC.Util.FHIRTranformer).%New(tXSLPath)
    Set tTranformer.Debug=1,tTranformer.DebugPath=""
    If $GET(^HCC("FHIR","Transfer","DebugPath"))'=""
	{
    	Set tTranformer.DebugPath=$GET(^HCC("FHIR","Transfer","DebugPath"))_pDocPK_"SDA.xml"
	}
	
	try
	{
		Set tCount=0
		Set tStm = ##class(%SQL.Statement).%New()
		Set tSC = tStm.%Prepare(.tSQL)
		Return:($$$ISERR(tSC)) tSC
		
		Set tRS = tStm.%Execute(pDocPK)
		While tRS.%Next()
	  	{
		  	D $I(tCount)
			Set tTmp = tRS.%GetData(1),tDocPK = tRS.%GetData(2), tLen = 32000, ^HCCStatus("tDocPK")=tDocPK
			Set tDocContent=tTmp.Read(.tLen)
			While tLen>0
			{
				Set tDocContent=tDocContent_tTmp.Read(.tLen)
			}
			// base64 decode
			Set tPlainContent = $system.Encryption.Base64Decode(tDocContent)
			Set tPlainContent = $ZCVT(tPlainContent,"I","UTF8")
			Set tPlainContent = $Replace(tPlainContent,x,"")
			
			//debug mode
			If $GET(^HCC("FHIR","Transfer","DebugPath"))'=""
			{
				Set tFHIRDebugPath=$G(^HCC("FHIR","Transfer","DebugPath"))
				Set tDebug=##class(%Stream.FileCharacter).%New()
			    Set tDebug.TranslateTable="UTF8"
				Set tDebugFile= tFHIRDebugPath_tDocPK_".xml"
				Set tSC=tDebug.LinkToFile(tDebugFile)
				;w tPlainContent,!
		    	Do tDebug.Write(tPlainContent)
		    	Do tDebug.%Save(),tDebug.%Close()
			}
	    	
	   		w "XML saved",!
			set tStream = ##class(%Stream.TmpCharacter).%New()
			Do tStream.Write(tPlainContent)
			// transform to FHIR
			Set tFHIR=""			
			Set tSC = tTranformer.TransferHCCDocStream2FHIR(tStream,.tFHIR)
			;w tDocPK," generated",!
			w " generated:",tSC,!
			Return:($$$ISERR(tSC)) tSC
			
			//debug mode
			If $GET(^HCC("FHIR","Transfer","DebugPath"))'=""
			{
				Set tFHIRDebugPath=$G(^HCC("FHIR","Transfer","DebugPath"))
				Set tDebug=##class(%Stream.FileCharacter).%New()
			    Set tDebug.TranslateTable="UTF8"
				Set tDebugFile= tFHIRDebugPath_tDocPK_".json"
				Set tSC=tDebug.LinkToFile(tDebugFile)
				;Return:($$$ISERR(tSC)) tSC
				
		    	Do tDebug.Write(tFHIR.Read())
		    	Do tDebug.%Save(),tDebug.%Close()
		    	;w "debugfile saved",!
		    	Do tFHIR.Rewind()
			}
	    	
	    	// revise FHIR based on FHIR repository
	    	Set tTarget=""
	    	Set tSC = ##class(HCC.Util.FHIR).ReviseFHIRStream(tFHIR,.tTarget)
	    	;w tDocPK," revised",!
	    	w "revised:",tSC,!
	    	//debug mode
			If $GET(^HCC("FHIR","Transfer","DebugPath"))'=""
			{
				Set tFHIRDebugPath=$G(^HCC("FHIR","Transfer","DebugPath"))
				Set tDebug=##class(%Stream.FileCharacter).%New()
			    Set tDebug.TranslateTable="UTF8"
				Set tDebugFile= tFHIRDebugPath_tDocPK_"Revised.json"
				Set tSC=tDebug.LinkToFile(tDebugFile)
		    	Do tDebug.Write(tTarget.Read())
		    	Do tDebug.%Save(),tDebug.%Close()
			}
	    	Return:($$$ISERR(tSC)) tSC
			// upload to FHIR repository
			/*Set tSC = ##class(HCC.Util.FHIR).UploadSingleStream(,,tTarget)
			w tSC,!
			Return:($$$ISERR(tSC)) tSC
			w tDocPK," uploaded",!
			*/
	    	Set tPlainContent=""
	    	Do tTmp.%Close(),tTarget.%Close(),tFHIR.%Close(),tStream.%Close()
		}
		Do tRS.%Close(),tStm.%Close()
		w tCount," processed",!
	}
	catch(e)
	{
		;Write $system.OBJ.DisplayError(%objlasterror),!
		zw %objlasterror
		Set ^HCCStatus($I(^HCCStatus),"Error",tDocPK)=$system.Status.GetErrorText(%objlasterror)
		Q
	}
	Q tSC
}

ClassMethod Test3()
{
	;s x="2. 影像表现：腰椎序列如常，生理曲度存在。多发椎体缘骨质增生。腰2/3-腰5/骶1椎间盘T2WI信号不均匀减 低。腰2/3椎间盘膨出并向后突出，腰4/5椎间盘膨出，腰5/骶1椎间盘向左后突出，相应硬膜囊受 压，腰5/骶1左侧神经根稍受压，椎管未见明显狭窄。脊髓圆锥及马尾信号未见明显异常。 诊断意见： 腰椎退行性变。 腰2/3椎间盘膨出并突出，腰4/5椎间盘膨出，腰5/骶1椎间盘突出。"
	s x="2. 影像表现：   腰椎序列如常，生理曲度存在。多发椎体缘骨质增生。腰2/3-腰5/骶1椎间盘T2WI信号不均匀减 低。腰2/3椎间盘膨出并向后突出，腰4/5椎间盘膨出，腰5/骶1椎间盘向左后突出，相应硬膜囊受 压，腰5/骶1左侧神经根稍受压，椎管未见明显狭窄。脊髓圆锥及马尾信号未见明显异常。 诊断意见： 腰椎退行性变。 腰2/3椎间盘膨出并突出，腰4/5椎间盘膨出，腰5/骶1椎间盘突出。"
	set matcher=##class(%Regex.Matcher).%New("[ \r\n\t\S]+") 
	w matcher.Match(x)
}

}
